EXPLAIN命令是查看查询优化器如何决定执行查询的主要方法。学会解释EXPLAIN将帮助了解Mysql优化器是如何工作的。
要使用EXPLAIN,只需在查询中的SELECT的关键字前面增加EXPLAIN这个词。mysql会在查询上设置一个标记。 当执行查询时,这个标记会使其返回关于在执行计划中的每一步的信息,而不是执行它。
它会返回一行或者多行信息,在查询中每个表在输出中只有一行。如果查询是两个表的联接,那么输出中将会有两行。 别名表单算为一个表,因此,如果把一个表和自己联接,输出中也会有两行。“表“的意思在这里相当广:可以是一个子查询,一个UNION结果,等等。
MySQL Explain只能解释SELECT查询,并不会对存储过程和INSERT,UPDATE,DELETE或者其它语句做解释。 然而,你可以重写某些非SELECT查询以利用EXPLAIN。为了达到这个目的,只需要将该语句转化成一个等价的访问 所有相同列的SELECT。任何提及的列都必须在SELECT列表,关联子句,或者WHERE子句中。
显示计划时,对于写查询并没有“等价”的读查询。
注:Mysql5.6允许解释非SELECT查询。
EXPLAIN的输出的总是有相同的列,下面具体说一下在EXPLAIN结果中每一列的意义。有一点也是要记住的, 输出的行以Mysql实际执行的查询部分的顺序出现,而这个顺序不总是与其在原生的SQL中的一致。
这一列总是包含一个编号,标识SELECT所属的行。
Mysql将SELECT查询分为简单和复杂类型,复杂类型可分为三大类:简单子查询,所谓的派生表,以及UNION查询。
这一列显示了对应行是简单还是复杂SELECT(如果是后者,那么是三种复杂类型中的哪一种),SIMPLE意味着查询不包括子查询和UNION。 如果查询有任何复杂部分的子部分,则最外层部分标记为PRIMARY,其余部分主要如下:
名称 | 解释 | 备注 |
---|---|---|
SUBQUERY | 包含在SELECT列表中的子查询中的SELECT标记为SUBQUERY | 不在FROM子句中 |
DERIVED | 用来表示包含在FROM子句的子查询中的SELECT | 派生表 |
UNION | 在UNION中的第二个和随后的SELECT |
还可能被标记成UNION RESULT,DEPENDENT和UNCACHEABLE这些不常见的。
显示对应行正在访问哪个表,通常是那个表或者是该表的别名。
该列表示关联类型,准确来说是访问类型,换言之MySQL如何查找表中的行。下面是最重要的访问方法,依次从最差到最优。
名称 | 描述 | 备注 |
---|---|---|
ALL | 全表扫描 | 例外就是在查询中使用了limit或者Extra列中显示“Using distinct/not exists |
Index | 类似全表扫描,只是扫描表时按索引次序进行而不是行 | |
range | 范围扫描就是一个有限制的索引扫描 | 它开始于索引里的某一个点,返回匹配这个值域的行 |
ref | 索引访问(索引查找) | 返回所有匹配某个单个值的行(可能有多个) |
eq-ref | 特殊的索引查找 | mysql知道最多只返回一条符合条件的记录(例如使用主键) |
const,system | 当MySQL能对查询的某部分进行优化并将其转换成一个常量时 | 例如通过将某一行的主键放入where子句来选取此行的主键 |
null | mysql在优化阶段分解查询语句,在执行阶段不用访问表或者索引 | 例如单独查询索引列的最小值 |
这一列显示了查询可以使用哪些索引。
这一列显示了mysql决定采用哪个索引来优化对该表的访问。
该列显示了MySQL在索引里使用的字节数。如果mysql正在使用的只是索引里的某些列,那么就可以用这个值计算出具体是哪些列。
这一列显示了之前的表在key列记录的索引中查找值所用的列数或者常量。
这一列是MySQL估计为了找到所需的行而要读取的行数。
它显示的是针对表里符合某个条件(where子句或者联接条件)的记录数的百分比所做的一个悲观估计。
这一列包含的是不适合在其它列显示的额外信息。
常见的重要的值如下:
名称 | 描述 |
---|---|
Using index | 此值表示MySQL将使用覆盖索引 ,以避免访问表 |
Using where | 这意味着mysql服务器将在存储引擎检查行后再进行过滤 |
Using temporary | 这意味着mysql在对查询结果排序时会使用一个临时表 |
Using filesort | mysql会对结果使用一个外部索引排序 |
Range checked for each record(index map:N) | 意味着没有好用的索引,新的索引将在联接的每一行上重新估算 |